bitkeeper revision 1.1159.207.3 (41d40e9b3_4vSbRgi7pJ9tnNxCToeQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 30 Dec 2004 14:20:11 +0000 (14:20 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 30 Dec 2004 14:20:11 +0000 (14:20 +0000)
New generic I/O ring macros from Andrew Warfield and Tim Deegan.
Currently only used for block-device channels.

.rootkeys
linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c
linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h
linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c
linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c
linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h
xen/include/public/io/blkif.h
xen/include/public/io/ring.h [new file with mode: 0644]

index 8c10a9751c16047d8d0ac54fb0edc69deb1b0471..bc4f73b249ff3d7fbd8164819ebad274b7e3b3dc 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40dc4076pVeE1kEEWzcUaNZin65kCA xen/include/public/io/domain_controller.h
 41c0c412FLc0gunlJl91qMYscFtXVA xen/include/public/io/ioreq.h
 40f5623cTZ80EwjWUBlh44A9F9i_Lg xen/include/public/io/netif.h
+41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
 4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
 40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
 404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
index b3d195cb0db841e7dff444a7efd3aaf6491646cb..6167f6061bf08fa3eb7776ace1f0e10d95feaaee 100644 (file)
@@ -74,12 +74,11 @@ static kmem_cache_t *buffer_head_cachep;
  * If the tap driver is used, we may get pages belonging to either the tap
  * or (more likely) the real frontend.  The backend must specify which domain
  * a given page belongs to in update_va_mapping though.  For the moment, 
- * we pass in the domid of the real frontend in PROBE messages and store 
- * this value in alt_dom.  Then on mapping, we try both.  This is a Guiness 
- * book of records-calibre grim hack, and represents a bit of a security risk.
- * Grant tables will soon solve the problem though!
+ * the tap rewrites the ID field of the request to contain the request index
+ * and the id of the real front end domain.
  */
-static domid_t alt_dom = 0;
+#define BLKTAP_COOKIE 0xbeadfeed
+static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
 #endif
 
 static int do_block_io_op(blkif_t *blkif, int max_to_do);
@@ -279,17 +278,16 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
 
 static int do_block_io_op(blkif_t *blkif, int max_to_do)
 {
-    blkif_ring_t *blk_ring = blkif->blk_ring_base;
+    blkif_back_ring_t *blk_ring = &blkif->blk_ring;
     blkif_request_t *req;
-    BLKIF_RING_IDX i, rp;
+    RING_IDX i, rp;
     int more_to_do = 0;
 
-    rp = blk_ring->req_prod;
+    rp = blk_ring->sring->req_prod;
     rmb(); /* Ensure we see queued requests up to 'rp'. */
 
-    /* Take items off the comms ring, taking care not to overflow. */
-    for ( i = blkif->blk_req_cons; 
-          (i != rp) && ((i-blkif->blk_resp_prod) != BLKIF_RING_SIZE);
+    for ( i = blk_ring->req_cons; 
+         (i != rp) && !RING_REQUEST_CONS_OVERFLOW(BLKIF_RING, blk_ring, i);
           i++ )
     {
         if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
@@ -298,7 +296,7 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
             break;
         }
         
-        req = &blk_ring->ring[MASK_BLKIF_IDX(i)].req;
+        req = RING_GET_REQUEST(BLKIF_RING, blk_ring, i);
         switch ( req->operation )
         {
         case BLKIF_OP_READ:
@@ -312,14 +310,13 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
 
         default:
             DPRINTK("error: unknown block io operation [%d]\n",
-                    blk_ring->ring[i].req.operation);
-            make_response(blkif, blk_ring->ring[i].req.id, 
-                          blk_ring->ring[i].req.operation, BLKIF_RSP_ERROR);
+                    req->operation);
+            make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
             break;
         }
     }
 
-    blkif->blk_req_cons = i;
+    blk_ring->req_cons = i;
     return more_to_do;
 }
 
@@ -339,24 +336,26 @@ static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
 
 #ifdef CONFIG_XEN_BLKDEV_TAP_BE
     /* Grab the real frontend out of the probe message. */
-    alt_dom = (domid_t)req->frame_and_sects[1];
+    if (req->frame_and_sects[1] == BLKTAP_COOKIE) 
+        blkif->is_blktap = 1;
 #endif
-    
+
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
     if ( HYPERVISOR_update_va_mapping_otherdomain(
         MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
         (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
-        0, blkif->domid) ) {
-#ifdef CONFIG_XEN_BLKDEV_TAP_BE
-        /* That didn't work.  Try alt_dom. */
-        if ( HYPERVISOR_update_va_mapping_otherdomain(
-            MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
-            (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
-            0, alt_dom) )
-            goto out;
-#else  
+        0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
+        
+        goto out;
+#else
+    if ( HYPERVISOR_update_va_mapping_otherdomain(
+        MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
+        (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
+        0, blkif->domid) ) 
+        
         goto out;
 #endif
-    }
     
     rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0), 
                     PAGE_SIZE / sizeof(vdisk_t));
@@ -441,7 +440,7 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
         mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot;
         mcl[i].args[2] = 0;
 #ifdef CONFIG_XEN_BLKDEV_TAP_BE
-        mcl[i].args[3] = (alt_dom != 0) ? alt_dom : blkif->domid;
+        mcl[i].args[3] = (blkif->is_blktap) ? ID_TO_DOM(req->id) : blkif->domid;
 #else
         mcl[i].args[3] = blkif->domid;
 #endif
@@ -558,16 +557,17 @@ static void make_response(blkif_t *blkif, unsigned long id,
 {
     blkif_response_t *resp;
     unsigned long     flags;
+    blkif_back_ring_t *blk_ring = &blkif->blk_ring;
 
     /* Place on the response ring for the relevant domain. */ 
     spin_lock_irqsave(&blkif->blk_ring_lock, flags);
-    resp = &blkif->blk_ring_base->
-        ring[MASK_BLKIF_IDX(blkif->blk_resp_prod)].resp;
+    resp = RING_GET_RESPONSE(BLKIF_RING, blk_ring, blk_ring->rsp_prod_pvt);
     resp->id        = id;
     resp->operation = op;
     resp->status    = st;
     wmb(); /* Ensure other side can see the response fields. */
-    blkif->blk_ring_base->resp_prod = ++blkif->blk_resp_prod;
+    blk_ring->rsp_prod_pvt++;
+    RING_PUSH_RESPONSES(BLKIF_RING, blk_ring);
     spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
 
     /* Kick the relevant domain. */
index 4a12ca8fe9644184aa5d3368c1462ec29244d3f0..1df08d43cde14150877e373134b80f1484e7b187 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm-xen/ctrl_if.h>
 #include <asm-xen/hypervisor.h>
 #include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
 
 #if 0
 #define ASSERT(_p) \
@@ -36,19 +37,17 @@ struct block_device;
 
 typedef struct blkif_st {
     /* Unique identifier for this interface. */
-    domid_t          domid;
-    unsigned int     handle;
+    domid_t           domid;
+    unsigned int      handle;
     /* Physical parameters of the comms window. */
-    unsigned long    shmem_frame;
-    unsigned int     evtchn;
-    int              irq;
+    unsigned long     shmem_frame;
+    unsigned int      evtchn;
+    int               irq;
     /* Comms information. */
-    blkif_ring_t    *blk_ring_base; /* ioremap()'ed ptr to shmem_frame. */
-    BLKIF_RING_IDX     blk_req_cons;  /* Request consumer. */
-    BLKIF_RING_IDX     blk_resp_prod; /* Private version of resp. producer. */
+    blkif_back_ring_t blk_ring;
     /* VBDs attached to this interface. */
-    rb_root_t        vbd_rb;        /* Mapping from 16-bit vdevices to VBDs. */
-    spinlock_t       vbd_lock;      /* Protects VBD mapping. */
+    rb_root_t         vbd_rb;        /* Mapping from 16-bit vdevices to VBDs.*/
+    spinlock_t        vbd_lock;      /* Protects VBD mapping. */
     /* Private fields. */
     enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
     /*
@@ -56,6 +55,10 @@ typedef struct blkif_st {
      * We therefore need to store the id from the original request.
      */
     u8               disconnect_rspid;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+    /* Is this a blktap frontend */
+    unsigned int     is_blktap;
+#endif
     struct blkif_st *hash_next;
     struct list_head blkdev_list;
     spinlock_t       blk_ring_lock;
index 4196014597fb4d56c0f14e086988b955144a4f2b..087e02d6202f8bfe43e2ceacf3d558d090ad1ad7 100644 (file)
@@ -39,7 +39,7 @@ static void __blkif_disconnect_complete(void *arg)
      * must still be notified to the remote driver.
      */
     unbind_evtchn_from_irq(blkif->evtchn);
-    vfree(blkif->blk_ring_base);
+    vfree(blkif->blk_ring.sring);
 
     /* Construct the deferred response message. */
     cmsg.type         = CMSG_BLKIF_BE;
@@ -149,14 +149,15 @@ void blkif_destroy(blkif_be_destroy_t *destroy)
 
 void blkif_connect(blkif_be_connect_t *connect)
 {
-    domid_t       domid  = connect->domid;
-    unsigned int  handle = connect->blkif_handle;
-    unsigned int  evtchn = connect->evtchn;
-    unsigned long shmem_frame = connect->shmem_frame;
+    domid_t        domid  = connect->domid;
+    unsigned int   handle = connect->blkif_handle;
+    unsigned int   evtchn = connect->evtchn;
+    unsigned long  shmem_frame = connect->shmem_frame;
     struct vm_struct *vma;
-    pgprot_t      prot;
-    int           error;
-    blkif_t      *blkif;
+    pgprot_t       prot;
+    int            error;
+    blkif_t       *blkif;
+    blkif_sring_t *sring;
 
     blkif = blkif_find_by_handle(domid, handle);
     if ( unlikely(blkif == NULL) )
@@ -195,11 +196,13 @@ void blkif_connect(blkif_be_connect_t *connect)
         vfree(vma->addr);
         return;
     }
-
+    sring = (blkif_sring_t *)vma->addr;
+    SHARED_RING_INIT(BLKIF_RING, sring);
+    BACK_RING_INIT(BLKIF_RING, &blkif->blk_ring, sring);
+    
     blkif->evtchn        = evtchn;
     blkif->irq           = bind_evtchn_to_irq(evtchn);
     blkif->shmem_frame   = shmem_frame;
-    blkif->blk_ring_base = (blkif_ring_t *)vma->addr;
     blkif->status        = CONNECTED;
     blkif_get(blkif);
 
index 1d65f29b45d98d25594fffda5c5eb8f2de4c512e..e3f345ac9b2871915538ec1f9845b66c3a8607a1 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
  * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
  * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
  * 
  * This file may be distributed separately from the Linux kernel, or
  * incorporated into other software packages, subject to the following license:
@@ -84,20 +85,14 @@ static unsigned int blkif_irq = 0;
 static int blkif_control_rsp_valid;
 static blkif_response_t blkif_control_rsp;
 
-static blkif_ring_t *blk_ring = NULL;
-static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */
-static BLKIF_RING_IDX req_prod;  /* Private request producer.         */
+static blkif_front_ring_t blk_ring;
 
 unsigned long rec_ring_free;
-blkif_request_t rec_ring[BLKIF_RING_SIZE];
+blkif_request_t rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)];
 
 static int recovery = 0;           /* "Recovery in progress" flag.  Protected
                                     * by the blkif_io_lock */
 
-/* We plug the I/O ring if the driver is suspended or if the ring is full. */
-#define BLKIF_RING_FULL (((req_prod - resp_cons) == BLKIF_RING_SIZE) || \
-                         (blkif_state != BLKIF_STATE_CONNECTED))
-
 static void kick_pending_request_queues(void);
 
 int __init xlblk_init(void);
@@ -108,7 +103,7 @@ static inline int GET_ID_FROM_FREELIST( void )
 {
     unsigned long free = rec_ring_free;
 
-    if ( free > BLKIF_RING_SIZE )
+    if ( free > RING_SIZE(BLKIF_RING, &blk_ring) )
         BUG();
 
     rec_ring_free = rec_ring[free].id;
@@ -169,8 +164,7 @@ static inline void translate_req_to_mfn(blkif_request_t *xreq,
 static inline void flush_requests(void)
 {
     DISABLE_SCATTERGATHER();
-    wmb(); /* Ensure that the frontend can see the requests. */
-    blk_ring->req_prod = req_prod;
+    RING_PUSH_REQUESTS(BLKIF_RING, &blk_ring);
     notify_via_evtchn(blkif_evtchn);
 }
 
@@ -343,7 +337,7 @@ static int blkif_queue_request(struct request *req)
         return 1;
 
     /* Fill out a communications ring structure. */
-    ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
+    ring_req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
     id = GET_ID_FROM_FREELIST();
     rec_ring[id].id = (unsigned long) req;
 
@@ -372,8 +366,8 @@ static int blkif_queue_request(struct request *req)
         }
     }
 
-    req_prod++;
-
+    blk_ring.req_prod_pvt++;
+    
     /* Keep a private copy so we can reissue requests when recovering. */
     translate_req_to_pfn( &rec_ring[id], ring_req);
 
@@ -400,7 +394,7 @@ void do_blkif_request(request_queue_t *rq)
             continue;
         }
 
-        if ( BLKIF_RING_FULL )
+        if ( RING_FULL(BLKIF_RING, &blk_ring) )
         {
             blk_stop_queue(rq);
             break;
@@ -426,9 +420,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
 {
     struct request *req;
     blkif_response_t *bret;
-    BLKIF_RING_IDX i, rp;
+    RING_IDX i, rp;
     unsigned long flags; 
-
+    
     spin_lock_irqsave(&blkif_io_lock, flags);     
 
     if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) || 
@@ -437,18 +431,17 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
         spin_unlock_irqrestore(&blkif_io_lock, flags);
         return IRQ_HANDLED;
     }
-
-    rp = blk_ring->resp_prod;
+    
+    rp = blk_ring.sring->rsp_prod;
     rmb(); /* Ensure we see queued responses up to 'rp'. */
 
-    for ( i = resp_cons; i != rp; i++ )
+    for ( i = blk_ring.rsp_cons; i != rp; i++ )
     {
        unsigned long id;
-        bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
 
+        bret = RING_GET_RESPONSE(BLKIF_RING, &blk_ring, i);
        id = bret->id;
        req = (struct request *)rec_ring[id].id;
-
        blkif_completion( &rec_ring[id] );
 
        ADD_ID_TO_FREELIST(id); /* overwrites req */
@@ -477,9 +470,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
             BUG();
         }
     }
-    
-    resp_cons = i;
 
+    blk_ring.rsp_cons = i;
+    
     kick_pending_request_queues();
 
     spin_unlock_irqrestore(&blkif_io_lock, flags);
@@ -533,10 +526,11 @@ static void kick_pending_request_queues(void)
 {
     /* We kick pending request queues if the ring is reasonably empty. */
     if ( (nr_pending != 0) && 
-         ((req_prod - resp_cons) < (BLKIF_RING_SIZE >> 1)) )
+         (RING_PENDING_REQUESTS(BLKIF_RING, &blk_ring) < 
+            (RING_SIZE(&blk_ring) >> 1)) )
     {
         /* Attempt to drain the queue, but bail if the ring becomes full. */
-        while ( (nr_pending != 0) && !BLKIF_RING_FULL )
+        while ( (nr_pending != 0) && !RING_FULL(BLKIF_RING, &blk_ring) )
             do_blkif_request(pending_queues[--nr_pending]);
     }
 }
@@ -830,8 +824,8 @@ static int blkif_queue_request(unsigned long   id,
              (sg_dev == device) &&
              (sg_next_sect == sector_number) )
         {
-
-            req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod-1)].req;
+            req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, 
+                    blk_ring.rsp_prod_pvt - 1);
             bh = (struct buffer_head *)id;
            
             bh->b_reqnext = (struct buffer_head *)rec_ring[req->id].id;
@@ -851,7 +845,7 @@ static int blkif_queue_request(unsigned long   id,
 
             return 0;
         }
-        else if ( BLKIF_RING_FULL )
+        else if ( RING_FULL(BLKIF_RING, &blk_ring) )
         {
             return 1;
         }
@@ -868,7 +862,7 @@ static int blkif_queue_request(unsigned long   id,
     }
 
     /* Fill out a communications ring structure. */
-    req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
+    req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
 
     xid = GET_ID_FROM_FREELIST();
     rec_ring[xid].id = id;
@@ -880,11 +874,11 @@ static int blkif_queue_request(unsigned long   id,
     req->nr_segments   = 1;
     req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect;
 
-    req_prod++;
-
     /* Keep a private copy so we can reissue requests when recovering. */    
     translate_req_to_pfn(&rec_ring[xid], req );
 
+    blk_ring.req_prod_pvt++;
+    
     return 0;
 }
 
@@ -973,7 +967,7 @@ void do_blkif_request(request_queue_t *rq)
 
 static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
 {
-    BLKIF_RING_IDX i, rp; 
+    RING_IDX i, rp; 
     unsigned long flags; 
     struct buffer_head *bh, *next_bh;
     
@@ -985,14 +979,15 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
         return;
     }
 
-    rp = blk_ring->resp_prod;
+    rp = blk_ring.rsp_prod;
     rmb(); /* Ensure we see queued responses up to 'rp'. */
 
-    for ( i = resp_cons; i != rp; i++ )
+    for ( i = blk_ring.rsp_cons; i != rp; i++ )
     {
        unsigned long id;
-        blkif_response_t *bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
-
+        blkif_response_t *bret;
+        
+        bret = RING_GET_RESPONSE(BLKIF_RING, &blkif_ring, i);
        id = bret->id;
        bh = (struct buffer_head *)rec_ring[id].id; 
 
@@ -1022,10 +1017,9 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
         default:
             BUG();
         }
-    }
-    
-    resp_cons = i;
 
+    blk_ring.rsp_cons = i;
+    
     kick_pending_request_queues();
 
     spin_unlock_irqrestore(&io_request_lock, flags);
@@ -1039,31 +1033,33 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
 void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
 {
     unsigned long flags, id;
+    blkif_request_t *req_d;
 
  retry:
-    while ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
+    while ( RING_FULL(BLKIF_RING, &blk_ring) )
     {
         set_current_state(TASK_INTERRUPTIBLE);
         schedule_timeout(1);
     }
 
     spin_lock_irqsave(&blkif_io_lock, flags);
-    if ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
+    if ( RING_FULL(BLKIF_RING, &blk_ring) )
     {
         spin_unlock_irqrestore(&blkif_io_lock, flags);
         goto retry;
     }
 
     DISABLE_SCATTERGATHER();
-    blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req = *req;    
+    req_d = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
+    *req_d = *req;    
 
     id = GET_ID_FROM_FREELIST();
-    blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req.id = id;
+    req_d->id = id;
     rec_ring[id].id = (unsigned long) req;
 
     translate_req_to_pfn( &rec_ring[id], req );
 
-    req_prod++;
+    blk_ring.req_prod_pvt++;
     flush_requests();
 
     spin_unlock_irqrestore(&blkif_io_lock, flags);
@@ -1105,7 +1101,7 @@ static void blkif_send_interface_connect(void)
     blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
     
     msg->handle      = 0;
-    msg->shmem_frame = (virt_to_machine(blk_ring) >> PAGE_SHIFT);
+    msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT);
     
     ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
 }
@@ -1119,10 +1115,10 @@ static void blkif_free(void)
     spin_unlock_irq(&blkif_io_lock);
 
     /* Free resources associated with old device channel. */
-    if ( blk_ring != NULL )
+    if ( blk_ring.sring != NULL )
     {
-        free_page((unsigned long)blk_ring);
-        blk_ring = NULL;
+        free_page((unsigned long)blk_ring.sring);
+        blk_ring.sring = NULL;
     }
     free_irq(blkif_irq, NULL);
     blkif_irq = 0;
@@ -1138,10 +1134,14 @@ static void blkif_close(void)
 /* Move from CLOSED to DISCONNECTED state. */
 static void blkif_disconnect(void)
 {
-    if ( blk_ring != NULL )
-        free_page((unsigned long)blk_ring);
-    blk_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
-    blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
+    blkif_sring_t *sring;
+    
+    if ( blk_ring.sring != NULL )
+        free_page((unsigned long)blk_ring.sring);
+    
+    sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
+    SHARED_RING_INIT(BLKIF_RING, sring);
+    FRONT_RING_INIT(BLKIF_RING, &blk_ring, sring);
     blkif_state  = BLKIF_STATE_DISCONNECTED;
     blkif_send_interface_connect();
 }
@@ -1155,34 +1155,37 @@ static void blkif_reset(void)
 static void blkif_recover(void)
 {
     int i;
+    blkif_request_t *req;
 
     /* Hmm, requests might be re-ordered when we re-issue them.
      * This will need to be fixed once we have barriers */
 
     /* Stage 1 : Find active and move to safety. */
-    for ( i = 0; i < BLKIF_RING_SIZE; i++ )
+    for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
     {
         if ( rec_ring[i].id >= PAGE_OFFSET )
         {
-            translate_req_to_mfn(
-                &blk_ring->ring[req_prod].req, &rec_ring[i]);
-            req_prod++;
+            req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, 
+                    blk_ring.req_prod_pvt);
+            translate_req_to_mfn(req, &rec_ring[i]);
+            blk_ring.req_prod_pvt++;
         }
     }
 
     /* Stage 2 : Set up shadow list. */
-    for ( i = 0; i < req_prod; i++ ) 
+    for ( i = 0; i < blk_ring.req_prod_pvt; i++ ) 
     {
-        rec_ring[i].id = blk_ring->ring[i].req.id;             
-        blk_ring->ring[i].req.id = i;
-        translate_req_to_pfn(&rec_ring[i], &blk_ring->ring[i].req);
+        req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, i);
+        rec_ring[i].id = req->id;              
+        req->id = i;
+        translate_req_to_pfn(&rec_ring[i], req);
     }
 
     /* Stage 3 : Set up free list. */
-    for ( ; i < BLKIF_RING_SIZE; i++ )
+    for ( ; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
         rec_ring[i].id = i+1;
-    rec_ring_free = req_prod;
-    rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
+    rec_ring_free = blk_ring.req_prod_pvt;
+    rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
 
     /* blk_ring->req_prod will be set when we flush_requests().*/
     wmb();
@@ -1376,9 +1379,9 @@ int __init xlblk_init(void)
     printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n");
 
     rec_ring_free = 0;
-    for ( i = 0; i < BLKIF_RING_SIZE; i++ )
+    for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
        rec_ring[i].id = i+1;
-    rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
+    rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
 
     (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
                                     CALLBACK_IN_BLOCKING_CONTEXT);
index f50ce03bca70f4d5c89ffeca431eccc683ace732..487a83967e843a0fe206bc3647fe0d67fc0da2a7 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <asm-xen/xen-public/xen.h>
 #include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
index 8cd3696eb679640468eb6b8de0e781a6b3d12303..4108f4e545776607149fbb02036d00fd6320843f 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef __XEN_PUBLIC_IO_BLKIF_H__
 #define __XEN_PUBLIC_IO_BLKIF_H__
 
+#include <asm-xen/xen-public/io/ring.h>
+
 #define blkif_vdev_t   u16
 #define blkif_sector_t u64
 
@@ -52,27 +54,11 @@ typedef struct {
 #define BLKIF_RSP_OKAY    0 /* non-specific 'okay'  */
 
 /*
- * We use a special capitalised type name because it is _essential_ that all 
- * arithmetic on indexes is done on an integer type of the correct size.
- */
-typedef u32 BLKIF_RING_IDX;
-
-/*
- * Ring indexes are 'free running'. That is, they are not stored modulo the
- * size of the ring buffer. The following macro converts a free-running counter
- * into a value that can directly index a ring-buffer array.
+ * Generate blkif ring structures and types.
  */
-#define MASK_BLKIF_IDX(_i) ((_i)&(BLKIF_RING_SIZE-1))
-
-typedef struct {
-    BLKIF_RING_IDX req_prod;  /*  0: Request producer. Updated by front-end. */
-    BLKIF_RING_IDX resp_prod; /*  4: Response producer. Updated by back-end. */
-    union {                   /*  8 */
-        blkif_request_t  req;
-        blkif_response_t resp;
-    } PACKED ring[BLKIF_RING_SIZE];
-} PACKED blkif_ring_t;
 
+#define BLKIF_RING RING_PARAMS(blkif_request_t, blkif_response_t, PAGE_SIZE)
+DEFINE_RING_TYPES(blkif, BLKIF_RING);
 
 /*
  * BLKIF_OP_PROBE:
diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h
new file mode 100644 (file)
index 0000000..8efeac4
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Shared producer-consumer ring macros.
+ * Tim Deegan and Andrew Warfield November 2004.
+ */ 
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* This is horrible: it rounds a 32-bit unsigned constant down to the
+ * nearest power of two, by finding the highest set bit. */
+#define __RD2PO2(_x) (((_x) & 0x80000000) ? 0x80000000 :                \
+                      ((_x) & 0x40000000) ? 0x40000000 :                \
+                      ((_x) & 0x20000000) ? 0x20000000 :                \
+                      ((_x) & 0x10000000) ? 0x10000000 :                \
+                      ((_x) & 0x08000000) ? 0x08000000 :                \
+                      ((_x) & 0x04000000) ? 0x04000000 :                \
+                      ((_x) & 0x02000000) ? 0x02000000 :                \
+                      ((_x) & 0x01000000) ? 0x01000000 :                \
+                      ((_x) & 0x00800000) ? 0x00800000 :                \
+                      ((_x) & 0x00400000) ? 0x00400000 :                \
+                      ((_x) & 0x00200000) ? 0x00200000 :                \
+                      ((_x) & 0x00100000) ? 0x00100000 :                \
+                      ((_x) & 0x00080000) ? 0x00080000 :                \
+                      ((_x) & 0x00040000) ? 0x00040000 :                \
+                      ((_x) & 0x00020000) ? 0x00020000 :                \
+                      ((_x) & 0x00010000) ? 0x00010000 :                \
+                      ((_x) & 0x00008000) ? 0x00008000 :                \
+                      ((_x) & 0x00004000) ? 0x00004000 :                \
+                      ((_x) & 0x00002000) ? 0x00002000 :                \
+                      ((_x) & 0x00001000) ? 0x00001000 :                \
+                      ((_x) & 0x00000800) ? 0x00000800 :                \
+                      ((_x) & 0x00000400) ? 0x00000400 :                \
+                      ((_x) & 0x00000200) ? 0x00000200 :                \
+                      ((_x) & 0x00000100) ? 0x00000100 :                \
+                      ((_x) & 0x00000080) ? 0x00000080 :                \
+                      ((_x) & 0x00000040) ? 0x00000040 :                \
+                      ((_x) & 0x00000020) ? 0x00000020 :                \
+                      ((_x) & 0x00000010) ? 0x00000010 :                \
+                      ((_x) & 0x00000008) ? 0x00000008 :                \
+                      ((_x) & 0x00000004) ? 0x00000004 :                \
+                      ((_x) & 0x00000002) ? 0x00000002 :                \
+                      ((_x) & 0x00000001) ? 0x00000001 : 0x00000000)
+
+/* Given a shared ring, tell me how many entries there are in it.  The
+ * rule is: a ring contains as many entries as will fit, rounded down to
+ * the nearest power of two (so we can mask with (size-1) to loop
+ * around) */
+#define __SRING_SIZE(__params, __esize)                                 \
+    __RD2PO2((sizeof((__params)->size) - (2 * sizeof(RING_IDX))) / (__esize))
+#define SRING_SIZE(__params, __sringp)                                  \
+    __SRING_SIZE(__params, sizeof (__sringp)->ring[0])
+
+/*
+ *  Macros to make the correct C datatypes for a new kind of ring.
+ * 
+ *  To make a new ring datatype, you need to have two message structures,
+ *  let's say request_t, and response_t already defined.  You also need to
+ *  know how big the shared memory region you want the ring to occupy is
+ *  (PAGE_SIZE, of instance).
+ *
+ *  In a header where you want the ring datatype declared, you then do:
+ *
+ *   #define MY_RING RING_PARAMS(request_t, response_t, PAGE_SIZE)
+ *   DEFINE_RING_TYPES(mytag, MY_RING);
+ *
+ *  These expand out to give you a set of types, as you can see below.
+ *  The most important of these are:
+ *  
+ *     mytag_sring_t      - The shared ring.
+ *     mytag_front_ring_t - The 'front' half of the ring.
+ *     mytag_back_ring_t  - The 'back' half of the ring.
+ *
+ *  Use the RING_PARAMS define (MY_RING above) as a first parameter on all
+ *  the ring functions.  To initialize a ring in your code, on the front 
+ *  half, you do a:
+ *
+ *      mytag_front_ring_t front_ring;
+ *
+ *      SHARED_RING_INIT(MY_RING, (mytag_sring_t *)shared_page)
+ *      FRONT_RING_INIT(MY_RING, &front_ring, (mytag_sring_t *)shared_page)
+ *
+ *  Initializing the back follows similarly...
+ */
+         
+/*  NB: RING SIZING. (a note to ease future debugging...)
+ *
+ *  Passing size information into the ring macros is made difficult by 
+ *  the lack of a reasonable constant declaration in C.  To get around this,
+ *  the RING_PARAMS define places the requested size of the ring as the 
+ *  static size of the 'size' array in the anonymous RING_PARAMS struct.
+ *  While this struct is never actually instantiated, __SRING_SIZE is 
+ *  able to use sizeof() to get at the constant size.
+ */
+
+#define RING_PARAMS(__req_t, __rsp_t, __size)                           \
+((struct {                                                              \
+    char size[__size];                                                  \
+    __req_t req;                                                        \
+    __rsp_t rsp;                                                        \
+                                                                        \
+} *) 0)
+
+
+#define DEFINE_RING_TYPES(__name, __params)                             \
+                                                                        \
+/* Shared ring entry */                                                 \
+union __name##_sring_entry {                                            \
+    typeof ((__params)->req) req;                                       \
+    typeof ((__params)->rsp) rsp;                                       \
+} PACKED;                                                               \
+                                                                        \
+/* Shared ring page */                                                  \
+struct __name##_sring {                                                 \
+    RING_IDX req_prod;                                                  \
+    RING_IDX rsp_prod;                                                  \
+    union __name##_sring_entry                                          \
+        ring[__SRING_SIZE(__params, sizeof (union __name##_sring_entry))];        \
+} PACKED;                                                               \
+                                                                        \
+/* "Front" end's private variables */                                   \
+struct __name##_front_ring {                                            \
+    RING_IDX req_prod_pvt;                                              \
+    RING_IDX rsp_cons;                                                  \
+    struct __name##_sring *sring;                                       \
+};                                                                      \
+                                                                        \
+/* "Back" end's private variables */                                    \
+struct __name##_back_ring {                                             \
+    RING_IDX rsp_prod_pvt;                                              \
+    RING_IDX req_cons;                                                  \
+    struct __name##_sring *sring;                                       \
+};                                                                      \
+                                                                        \
+/* Syntactic sugar */                                                   \
+typedef struct __name##_sring __name##_sring_t;                         \
+typedef struct __name##_front_ring __name##_front_ring_t;               \
+typedef struct __name##_back_ring __name##_back_ring_t;
+
+/*
+ *   Macros for manipulating rings.  
+ * 
+ *   FRONT_RING_whatever works on the "front end" of a ring: here 
+ *   requests are pushed on to the ring and responses taken off it.
+ * 
+ *   BACK_RING_whatever works on the "back end" of a ring: here 
+ *   requests are taken off the ring and responses put on.
+ * 
+ *   N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.  
+ *   This is OK in 1-for-1 request-response situations where the 
+ *   requestor (front end) never has more than SRING_SIZE()-1
+ *   outstanding requests.
+ */
+
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_p, _s) do {                                   \
+    (_s)->req_prod = 0;                                                 \
+    (_s)->rsp_prod = 0;                                                 \
+} while(0)
+
+#define FRONT_RING_INIT(_p, _r, _s) do {                                \
+    (_r)->req_prod_pvt = 0;                                             \
+    (_r)->rsp_cons = 0;                                                 \
+    (_r)->sring = (_s);                                                 \
+} while (0)
+
+#define BACK_RING_INIT(_p, _r, _s) do {                                 \
+    (_r)->rsp_prod_pvt = 0;                                             \
+    (_r)->req_cons = 0;                                                 \
+    (_r)->sring = (_s);                                                 \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_p, _r, _s) do {                              \
+    (_r)->sring = (_s);                                                 \
+    (_r)->req_prod_pvt = (_s)->req_prod;                                \
+    (_r)->rsp_cons = (_s)->rsp_prod;                                    \
+} while (0)
+
+#define BACK_RING_ATTACH(_p, _r, _s) do {                               \
+    (_r)->sring = (_s);                                                 \
+    (_r)->rsp_prod_pvt = (_s)->rsp_prod;                                \
+    (_r)->req_cons = (_s)->req_prod;                                    \
+} while (0)
+
+
+/* How to mask off a number for use as an offset into a ring 
+ * N.B. This evalutes its second argument once but its first often */
+#define __SHARED_RING_MASK(_p, _s, _i)                                  \
+    ((_i) & (SRING_SIZE((_p), (_s)) - 1))
+
+/* How big is this ring? */
+#define RING_SIZE(_p, _r) SRING_SIZE((_p), (_r)->sring)
+
+/* How many empty slots are on a ring? */
+#define RING_PENDING_REQUESTS(_p, _r)                                   \
+   ( ((_r)->req_prod_pvt - (_r)->rsp_cons) )
+   
+/* Test if there is an empty slot available on the front ring. 
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_p, _r)                                               \
+    (((_r)->req_prod_pvt - (_r)->rsp_cons) == SRING_SIZE((_p), (_r)->sring))
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_p, _r)                           \
+   ( (_r)->rsp_cons != (_r)->sring->rsp_prod )
+   
+#define RING_HAS_UNCONSUMED_REQUESTS(_p, _r)                            \
+   ( ((_r)->req_cons != (_r)->sring->req_prod ) &&                      \
+     (((_r)->req_cons - (_r)->rsp_prod_pvt) !=                          \
+      SRING_SIZE((_p), (_r)->sring)) )
+      
+/* Test if there are messages waiting to be pushed. */
+#define RING_HAS_UNPUSHED_REQUESTS(_p, _r)                              \
+   ( (_r)->req_prod_pvt != (_r)->sring->req_prod )
+   
+#define RING_HAS_UNPUSHED_RESPONSES(_p, _r)                             \
+   ( (_r)->rsp_prod_pvt != (_r)->sring->rsp_prod )
+   
+
+/* Copy the private producer pointer into the shared ring so the other end 
+ * can see the updates we've made. */
+#define RING_PUSH_REQUESTS(_p, _r) do {                                 \
+    wmb();                                                              \
+    (_r)->sring->req_prod = (_r)->req_prod_pvt;                         \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_p, _r) do {                                \
+    wmb();                                                              \
+    (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt;                         \
+} while (0)
+
+/* Direct access to individual ring elements, by index.  
+ */
+#define RING_GET_REQUEST(_p, _r, _idx)                                  \
+ (&((_r)->sring->ring[                                                  \
+     __SHARED_RING_MASK((_p), (_r)->sring, (_idx))                      \
+     ].req))
+
+#define RING_GET_RESPONSE(_p, _r, _idx)                                 \
+ (&((_r)->sring->ring[                                                  \
+     __SHARED_RING_MASK((_p), (_r)->sring, (_idx))                      \
+     ].rsp))   
+    
+/* Loop termination condition: Would the specified index overflow the 
+ * ring? 
+ */
+#define RING_REQUEST_CONS_OVERFLOW(_p, _r, _cons)                      \
+    (((_cons) - (_r)->rsp_prod_pvt) >= SRING_SIZE((_p), (_r)->sring))
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */